﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LED_Editor.Model;
using NUnit.Framework;
using LED_Editor.ControllerProgramming;

namespace LED_UnitTest
{

    public class TestControllerExProgrammingStrategy : ExtendedControllerProgrammingStrategy
    {
        

        public event ByteArrayReceivingEventHandler ByteArrayReceiving;

        private void OnByteArrayReceiving(ref byte[] bytes)
        {
            ByteArrayReceivingEventArgs args = new ByteArrayReceivingEventArgs() { Bytes = bytes };
            if (ByteArrayReceiving != null)
            {
                ByteArrayReceiving(this, args);
            }
            bytes = args.Bytes;
        }

        public override object WaitAnswer()
        {
            base.WaitAnswer(); 
            Log("Ожидание ответа...");

            byte[] answer = new byte[] { };

            Query ans = null;

            while (true)
            {
                OnByteArrayReceiving(ref answer);

                if (answer.Length >0)
                {
                    ans = new QueryParser().Parse(answer);

                    if (ans.Address == Address)
                        break;
                }
                else
                {
                    throw new ControllerException("Answer from controller has zero lenght");
                }

            }
            return ans;
        }

        public override bool IsReadyForProgramming
        {
            get
            {
                return true;
            }
        }

       
    }



    public class TestControllerEx : Controller
    {
        private TestControllerExProgrammingStrategy _controllerProgrammingStrategy;
      
        protected override IControllerProgrammingStrategy ControllerProgrammingStrategy
        {
            get
            {
                if (_controllerProgrammingStrategy == null)
                    _controllerProgrammingStrategy = new TestControllerExProgrammingStrategy();
                return _controllerProgrammingStrategy;
            }
        }

        public IControllerProgrammingStrategy Strategy
        {
            get
            {
                return ControllerProgrammingStrategy;
            }
        }



    }
    [TestFixture]
    public class ProgrammingControllerExAlgorithmTest
    {

        private TestControllerEx _controller;
        Queue<Query> controllerAnswers;
        [SetUp]
        public void Setup()
        {
            _controller = new TestControllerEx();
            _controller.Address = 1;
            _controller.Logging += new LoggingEventHandler(_controller_Logging);
            ((TestControllerExProgrammingStrategy)_controller.Strategy).ByteArrayReceiving += new ByteArrayReceivingEventHandler(_controller_ByteArrayReceiving);
        }

        void _controller_ByteArrayReceiving(object sender, ByteArrayReceivingEventArgs e)
        {
            //List<byte> bytes = new List<byte>();
            //bytes.Add(_controller.Address);
            //bytes.Add(Convert.ToByte(controllerAnswers.Dequeue()));
            Query query = controllerAnswers.Dequeue();
            e.Bytes = query.ToByteArray();
        }

        void _controller_Logging(object sender, LogEventArgs e)
        {
            Console.WriteLine(e.Message);
        }
        [Test]
        public void EchoSimpleQuery()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query enterProgrammingResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ENTER_PROG_MODE, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query finalizeResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.FINILIZE_PROG, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);

            //готов ли контроллер?

            EnqueueControllerAnswer(echoResponse);
            EnqueueControllerAnswer(enterProgrammingResponse);
            EnqueueControllerAnswer(finalizeResponse);

            _controller.Programme();
        }

        [Test,ExpectedException(typeof(ControllerException)) ]
        public void EchoInvalidResponse1()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Request, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);

            EnqueueControllerAnswer(echoResponse);

            _controller.Programme();
        }

        [Test, ExpectedException(typeof(ControllerException))]
        public void EchoInvalidResponse2()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.SET_COLOR, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);

            EnqueueControllerAnswer(echoResponse);

            _controller.Programme();
        }

        [Test, ExpectedException(typeof(ControllerException))]
        public void EchoInvalidResponse3()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.UNKNOWN_COMMAND, (byte)0, Query.EndByte);

            EnqueueControllerAnswer(echoResponse);

            _controller.Programme();
        }

        [Test, ExpectedException(typeof(ControllerException))]
        public void EchoInvalidResponse4()
        {
            Query echoResponse = Query.CreateInstance((byte)11, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.UNKNOWN_COMMAND, (byte)0, (byte)22);

            EnqueueControllerAnswer(echoResponse);

            _controller.Programme();
        }


        [Test]
        public void WriteFrameValidResponse()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query enterProgrammingResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ENTER_PROG_MODE, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query writeFrameResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.WRITE_FRAME, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query finalizeResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.FINILIZE_PROG, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            //готов ли контроллер?

            EnqueueControllerAnswer(echoResponse);
            EnqueueControllerAnswer(enterProgrammingResponse);
            EnqueueControllerAnswer(writeFrameResponse);
            EnqueueControllerAnswer(writeFrameResponse);
            EnqueueControllerAnswer(finalizeResponse);

            for (int i = 0; i < 2; i++)
            {
                _controller.Frames.Add(GetRandomFrame());
            }

            _controller.Programme();
        }

        [Test, ExpectedException(typeof(ControllerException))]
        public void WriteFrameInvalidResponse1()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query enterProgrammingResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ENTER_PROG_MODE, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query writeFrameResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.WRITE_FRAME, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            //готов ли контроллер?

            EnqueueControllerAnswer(echoResponse);
            EnqueueControllerAnswer(enterProgrammingResponse);
            EnqueueControllerAnswer(writeFrameResponse);
            EnqueueControllerAnswer(echoResponse);


            for (int i = 0; i < 2; i++)
            {
                _controller.Frames.Add(GetRandomFrame());
            }

            _controller.Programme();
        }

        [Test, ExpectedException(typeof(ControllerException))]
        public void WriteFrameInvalidResponse2()
        {
            Query echoResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ECHO, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query enterProgrammingResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.ENTER_PROG_MODE, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query writeFrameResponse = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.WRITE_FRAME, (byte)1, ErrorCodes.NO_ERROR, (byte)0, Query.EndByte);
            Query writeFrameResponseError = Query.CreateInstance(Query.StartByte, QueryType.Confirm, (byte)1, QueryCodes.WRITE_FRAME, (byte)1, ErrorCodes.CHECKSUM, (byte)0, Query.EndByte);
            //готов ли контроллер?

            EnqueueControllerAnswer(echoResponse);
            EnqueueControllerAnswer(enterProgrammingResponse);
            EnqueueControllerAnswer(writeFrameResponse);
            EnqueueControllerAnswer(writeFrameResponseError);


            for (int i = 0; i < 2; i++)
            {
                _controller.Frames.Add(GetRandomFrame());
            }

            _controller.Programme();
        }


        private void EnqueueControllerAnswer(QueryCodes query, byte address)
        {
            if (controllerAnswers == null)
            {
                controllerAnswers = new Queue<Query>();
            }
            controllerAnswers.Enqueue(Query.CreateInstance( query, address ));
        }

        private void EnqueueControllerAnswer(Query query)
        {
            if (controllerAnswers == null)
            {
                controllerAnswers = new Queue<Query>();
            }
            controllerAnswers.Enqueue(query);
        }


        private FrameStruct GetRandomFrame()
        {
            FrameStruct frame1 = new FrameStruct();
            frame1.Duration = 1;

            frame1.StartR = 20;
            frame1.StartG = 120;
            frame1.StartB = 220;

            frame1.EndR = 20;
            frame1.EndG = 120;
            frame1.EndB = 220;

            return frame1;

        }
    }

}
